package maze.net.server;

import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.util.Calendar;

import maze.contexts.MazeContext;
import maze.model.MazeGenerator;
import maze.model.MazeMap;
import maze.model.Player;
import maze.net.SGMPException;
import maze.pojo.Action;
import maze.utils.Async;

public class GameHouse {
	Socket player1;
	Socket player2;

	SGMPServerOutputStream out1, out2;
	SGMPServerInputStream in1, in2;

	public GameHouse(Socket player1, Socket player2) {
		this.player1 = player1;
		this.player2 = player2;
	}

	public void start() {
		Async.execute(new Runnable() {
			@Override
			public void run() {
				try {
					initStream();
					out1.sendPlayerReady(1);
					out2.sendPlayerReady(-1);
					in1.waitACK();
					in2.waitACK();
					long seed = Calendar.getInstance().getTimeInMillis();
					out1.sendCountdown(seed);
					out2.sendCountdown(seed);
					MazeMap map = new MazeGenerator(MazeContext.width,
							MazeContext.height, seed).generate();
					in1.waitACK();
					in2.waitACK();
					mainloop(map);
				} catch (EOFException e) {
				} catch (IOException | SGMPException e) {
				} finally {
					closeSocket(player1);
					closeSocket(player2);
				}
			}
		});
	}

	private void initStream() throws IOException {
		out1 = new SGMPServerOutputStream(player1);
		out2 = new SGMPServerOutputStream(player2);
		in1 = new SGMPServerInputStream(player1);
		in2 = new SGMPServerInputStream(player2);
	}

	private void closeSocket(Socket socket) {
		try {
			System.out.println("Close socket: " + socket);
			socket.close();
		} catch (IOException e1) {
			System.out.println("Close failed: " + e1.getMessage());
		}
	}

	private void mainloop(MazeMap map) throws IOException, SGMPException {
		System.out.println("Game start: " + player1);
		System.out.println("Game start: " + player2);
		Player p1 = new Player(1);
		Player p2 = new Player(-1);
		p1.setPosition(MazeContext.player1Start);
		p2.setPosition(MazeContext.player2Start);
		for (;;) {
			Action act1 = in1.readAction();
			Action act2 = in2.readAction();
			if ((act1.bit | act2.bit) != 0) {
				if (!map.canMove(p1, act1)) {
					act1 = Action.NONE;
				}
				if (!map.canMove(p2, act2)) {
					act2 = Action.NONE;
				}
				p1.move(act1);
				p2.move(act2);
			}
			int winner = 0;
			winner |= map.getGoalPosition(p1).equals(p1.getPosition()) ? 0b01
					: 0;
			winner |= map.getGoalPosition(p2).equals(p2.getPosition()) ? 0b10
					: 0;
			switch (winner) {
			case 0b01:
				out1.sendWin(act1, act2);
				out2.sendLose(act2, act1);
				break;
			case 0b10:
				out1.sendLose(act1, act2);
				out2.sendWin(act2, act1);
				break;
			case 0b11:
				out1.sendDraw(act1, act2);
				out2.sendDraw(act2, act1);
				break;
			default:
				out1.sendAction(act1, act2);
				out2.sendAction(act2, act1);
			}
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
			}
		}
	}
}
